home *** CD-ROM | disk | FTP | other *** search
- /* fully GNU plug-in test, but much cleaner, a little faster, and a lot smaller.
- (100 lines instead of 1000; binary is 4K instead of 18K on an i486-Linux)
- *loosely* based upon 'v7test.c' at uunet, but cleaned up and much enhanced.
- Charles Blake, 1994
-
- test has the following grammar:
- expr ::= bexpr | bexpr -o expr ;
- bexpr ::= primary | primary -a bexpr ;
- primary::= unary-operator operand
- | operand binary-operator operand
- | operand
- | "(" expr ")"
- | "!" expr
- unary-operator::= "-"+ r|w|x|f|d|s|t|e|S|p|c|b|L|h|k|u|g|O|G|z|n
- binary-operator::= -nt|-ot|-ef|=|!=|-eq|-ne|-ge|-gt|-le|-lt
- operand ::= <any legal UNIX file name>
- */
-
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- enum opnum { EOI,FILRD,FILWR,FILEX,FILND,FILID,FILGZ,FILTT,FILPR,FILSO,FILFF,
- FILCS,FILBS,FILSL,FILHL,FILSB,FILUI,FILGI,FILOU,FILOG,FNEWR,FOLDR,FSAME,
- STZER,STNZE,STEQL,STNEQ,INTEQ,INTNE,INTGE,INTGT,INTLE,INTLT,
- UNEGN,BAND,BOR,LPAREN,RPAREN,OPERAND};
-
- enum optype { UNOP, BINOP, BUNOP, BBINOP, PAREN }; /* maybe UNOP=1 ? */
-
- struct T_sop {
- char *text; enum opnum num; enum optype type;
- }T_ops[]={{"-r", FILRD, UNOP}, {"-w", FILWR, UNOP}, {"-x", FILEX, UNOP},
- {"-f", FILND, UNOP}, {"-d", FILID, UNOP}, {"-s", FILGZ, UNOP},
- {"-t", FILTT, UNOP}, {"-e", FILPR, UNOP}, {"-S", FILSO, UNOP},
- {"-p", FILFF, UNOP}, {"-c", FILCS, UNOP}, {"-b", FILBS, UNOP},
- {"-L", FILSL, UNOP}, {"-h", FILHL, UNOP}, {"-k", FILSB, UNOP},
- {"-u", FILUI, UNOP}, {"-g", FILGI, UNOP}, {"-O", FILOU, UNOP},
- {"-G", FILOG, UNOP}, {"-nt",FNEWR, BINOP}, {"-ot",FOLDR, BINOP},
- {"-ef",FSAME, BINOP}, {"-z", STZER, UNOP}, {"-n", STNZE, UNOP},
- {"=", STEQL, BINOP}, {"!=", STNEQ, BINOP}, {"-eq",INTEQ, BINOP},
- {"-ne",INTNE, BINOP}, {"-ge",INTGE, BINOP}, {"-gt",INTGT, BINOP},
- {"-le",INTLE, BINOP}, {"-lt",INTLT, BINOP}, {"!", UNEGN, BUNOP},
- {"-a", BAND, BBINOP},{"-o", BOR, BBINOP},{"(", LPAREN,PAREN},
- {")", RPAREN,PAREN}, { 0, 0, 0}};
-
- char** T_ip;
- struct T_sop *T_op;
- int T_error=0;
-
- #ifdef ADDON
-
- #include "addon.h"
- typedef enum bool { FALSE, TRUE } bool;
- extern void set(bool);
- void b_test(char* argv[]) {
- int i=0; /* truncate off possible trailing ']' s */
- while (argv[i]!=0) i++;
- if (argv[i-1][0]==']') argv[i-1]=0;
- T_ip = &argv[1];
- if (T_error==1) { set(FALSE); return; }
- if ((!(T_expr(T_lex(*T_ip)) && *++T_ip == 0))==0)
- set(TRUE);
- else
- set(FALSE);
- }
-
- #else
- int main(int argc, char* argv[]) {
- int i=0;
- while (argv[i]!=0) i++; /* truncate off possible trailing ']' s */
- if (argv[i-1][0]==']') argv[i-1]=0;
- T_ip = &argv[1];
- return(T_error==1 || !(T_expr(T_lex(*T_ip))&& *++T_ip == 0));
- }
- #endif /* ADDON */
-
- int T_expr(int n) {
- int res;
- if (n==EOI) { T_error=1; return 1; }
- res=T_bexpr(n);
- if (T_lex(*++T_ip)==BOR) return T_expr(T_lex(*++T_ip)) || res;
- T_ip--;
- return res;
- }
-
- int T_bexpr(int n) {
- int res;
- if (n == EOI) { T_error=1; return 1;}
- res = T_primary(n);
- if (T_lex(*++T_ip) == BAND) return T_bexpr(T_lex(*++T_ip)) && res;
- T_ip--;
- return res;
- }
-
- int T_primary(int n) {
- struct stat s, s2;
- char *opnd1, *opnd2;
- int res;
-
- if (n==EOI) { T_error=1; return 1;}
- if (n==UNEGN) return !T_expr(T_lex(*++T_ip));
- if (n==LPAREN) {
- res=T_expr(T_lex(*++T_ip));
- if (T_lex(*++T_ip) != RPAREN) { T_error=1; return 1;}
- return res;
- }
- if (n==OPERAND) {
- opnd1= *T_ip;
- (void) T_lex(*++T_ip);
- if (T_op && T_op->type==BINOP) {
- struct T_sop *op = T_op;
- if ((opnd2 = *++T_ip) == (char *)0) { T_error=1; return 1;}
- switch (op->num) {
- case STEQL: return strcmp(opnd1, opnd2) == 0;
- case STNEQ: return strcmp(opnd1, opnd2) != 0;
- case INTEQ: return atoi(opnd1) == atoi(opnd2);
- case INTNE: return atoi(opnd1) != atoi(opnd2);
- case INTGE: return atoi(opnd1) >= atoi(opnd2);
- case INTGT: return atoi(opnd1) > atoi(opnd2);
- case INTLE: return atoi(opnd1) <= atoi(opnd2);
- case INTLT: return atoi(opnd1) < atoi(opnd2);
- case FNEWR: return stat(opnd1,&s)==0 && stat(opnd2,&s2)==0 && s.st_mtime > s2.st_mtime;
- case FOLDR: return stat(opnd1,&s)==0 && stat(opnd2,&s2)==0 && s.st_mtime < s2.st_mtime;
- case FSAME: return stat(opnd1,&s)==0 && stat(opnd2,&s2)==0 && s.st_ino==s2.st_ino && s.st_dev==s2.st_dev;
- }
- }
- T_ip--;
- return strlen(opnd1) > 0;
- }
- /* unary expression */
- if (T_op->type != UNOP || *++T_ip == 0) { T_error=1; return 1;}
- if (n == STZER) return strlen(*T_ip) == 0;
- if (n == STNZE) return strlen(*T_ip) != 0;
- switch (n) {
- case FILRD: return access(*T_ip,R_OK)==0;
- case FILWR: return access(*T_ip,W_OK)==0;
- case FILEX: return access(*T_ip,X_OK)==0;
- case FILND: return stat(*T_ip,&s)==0 && ((s.st_mode & S_IFMT)!=S_IFDIR);
- case FILID: return stat(*T_ip,&s)==0 && ((s.st_mode & S_IFMT)==S_IFDIR);
- case FILGZ: return stat(*T_ip,&s)==0 && (s.st_size > 0L);
- case FILTT: T_error=1; return 1; /* unimplimented */
- case FILPR: return stat(*T_ip,&s)==0;
- case FILSO: return stat(*T_ip,&s)==0 && ((s.st_mode & S_IFMT)==S_IFSOCK);
- case FILFF: return stat(*T_ip,&s)==0 && ((s.st_mode & S_IFMT)==S_IFIFO);
- case FILCS: return stat(*T_ip,&s)==0 && ((s.st_mode & S_IFMT)==S_IFCHR);
- case FILBS: return stat(*T_ip,&s)==0 && ((s.st_mode & S_IFMT)==S_IFBLK);
- case FILSL: return lstat(*T_ip,&s)==0&& ((s.st_mode & S_IFMT)==S_IFLNK);
- case FILHL: return stat(*T_ip,&s)==0 && (s.st_nlink > 1);
- case FILSB: return stat(*T_ip,&s)==0 && (s.st_mode & S_ISVTX)==S_ISVTX;
- case FILUI: return stat(*T_ip,&s)==0 && (s.st_mode & S_ISUID)==S_ISUID;
- case FILGI: return stat(*T_ip,&s)==0 && (s.st_mode & S_ISGID)==S_ISGID;
- case FILOU: return stat(*T_ip,&s)==0 && (s.st_uid==geteuid());
- case FILOG: return stat(*T_ip,&s)==0 && (s.st_uid==geteuid());
- }
- }
-
- int T_lex(char* s) {
- struct T_sop *op = T_ops;
- if (s == 0) return EOI;
- while (op->text) {
- if (strcmp(s, op->text) == 0) {
- T_op = op;
- return op->num;
- }
- op++;
- }
- T_op = (struct T_sop *)0;
- return OPERAND;
- }
-